﻿#include "CircleBuffer.h"

CircleBuffer::CircleBuffer()
{
    rear = 0;
    head = 0;
    maxBuf = 0;
    buf = nullptr;
    isMutable = false;
}

CircleBuffer::~CircleBuffer()
{
    resetBuffer(0);
}

void CircleBuffer::copyData(char* data, int len)
{
    // 按字节拷贝
    for (int i = 0; i < len; i++)
    {
        buf[rear] = data[i];
        // 注意这里不能用rear++,既然是环形缓冲区，如果填充到底部之后，底部的索引要回到头部
        rear = (rear + 1) % maxBuf;
    }
}

// 处理数据
void CircleBuffer::pushData(char* data, int len)
{
    // 缓冲区剩余空间足够，正常存储
    if (maxBuf - dataLength() > len)
    {
        copyData(data, len);
    }
    else if (!isMutable)
    {
        // 移动头部丢弃数据
        moveHead(len);
        copyData(data, len);
    }
    else
    {
        // 开辟更大空间
        char* p = new char[maxBuf + len];
        int data_len = dataLength();

        // 将原有数据复制到新的缓存
        for (int i = 0; i < data_len; i++)
        {
            p[i] = buf[head];
            head = (head + 1) % maxBuf;
        }

        // 更新各种数据
        head = 0;
        rear = data_len;
        maxBuf = maxBuf + len;
        delete[] buf;
        buf = p;
        // 拷贝数据
        copyData(data, len);
    }
}

int CircleBuffer::dataLength()
{
    if (rear >= head)
    {
        return rear - head;
    }
    else
    {
        // 多次存取之后尾部索引有可能比头部索引要小
        return rear - head + maxBuf;
    }
}

void CircleBuffer::data(char* result, int len)
{
    // 获取数据，改变头部索引的位置
    for (int i = 0; i < len; i++)
    {
        result[i] = buf[head];
        // 头部的索引也有可能跑到底部，得让它能跑回来
        head = (head + 1) % maxBuf;
    }
}

// 重置缓冲区
void CircleBuffer::resetBuffer(int size, bool inMutable)
{
    isMutable = inMutable;

    rear = 0;
    head = 0;

    if (maxBuf == size)
    {
        return;
    }

    maxBuf = size;

    if (buf)
    {
        delete[] buf;
        buf = nullptr;
    }

    if (maxBuf)
    {
        buf = new char[maxBuf];
    }
}

bool CircleBuffer::empty()
{
    return head == rear;
}

void CircleBuffer::moveHead(int len)
{
    // 这里用%(取余符号)，这样就可以使头尾两个索引像一个环形一样
    head = (head + len) % maxBuf;
}
